﻿namespace Creek.UI.EFML.Base.Controls
{
    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Drawing.Drawing2D;
    using System.Windows.Forms;
    using System.Windows.Forms.Design;

    /// <seealso cref="http://beta.unclassified.de/code/dotnet/line/" />
    [Designer(typeof(LineDesigner))]
    public class Line : Control
    {
        #region Fields

        private Color borderColor = SystemColors.ControlText;

        /// <summary>
        /// 	Erforderliche Designervariable.
        /// </summary>
        private IContainer components;

        private Color dark3dColor = SystemColors.ControlDark;

        private DashStyle dashStyle = DashStyle.Solid;

        private bool internalResizing;

        private Color light3dColor = SystemColors.ControlLightLight;

        private Line3DStyle line3DStyle = Line3DStyle.Flat;

        private LineOrientation orientation = LineOrientation.Horizontal;

        private Pen pen1, pen2;

        private int prevHeight;

        private int prevWidth;

        #endregion

        #region Constructors and Destructors

        public Line()
        {
            this.InitializeComponent();

            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);

            this.DoubleBuffered = true;
            this.TabStop = false;

            this.pen1 = new Pen(this.borderColor, 1);
            this.pen2 = new Pen(this.borderColor, 1);
            this.prevWidth = this.Width;
            this.prevHeight = 100 /*Height*/;
            this.Orientation = LineOrientation.Horizontal;

            this.SizeChanged += this.Line_SizeChanged;
        }

        #endregion

        #region Public Properties

        [Description("Border color for solid border style")]
        [Category("Appearance")]
        public Color BorderColor
        {
            get
            {
                return this.borderColor;
            }
            set
            {
                this.borderColor = value;
                this.UpdatePens();
                this.Invalidate();
            }
        }

        [Description("Custom dark 3D color")]
        [Category("Appearance")]
        [DefaultValue(typeof(SystemColors), "ControlDark")]
        public Color Dark3dColor
        {
            get
            {
                return this.dark3dColor;
            }
            set
            {
                this.dark3dColor = value;
                this.UpdatePens();
                this.Invalidate();
            }
        }

        [Description("Border color for solid border style")]
        [Category("Appearance")]
        public DashStyle DashStyle
        {
            get
            {
                return this.pen1.DashStyle;
            }
            set
            {
                this.dashStyle = value;
                this.UpdatePens();
                this.Invalidate();
            }
        }

        //public new Size Size
        //{
        //    get
        //    {
        //        return base.Size;
        //    }
        //    set
        //    {
        //        int lineWidth = (borderStyle == BorderStyle.Fixed3D) ? 2 : 1;
        //        if (orientation == LineOrientation.Horizontal)
        //        {
        //            base.Size = new Size(Content.Width, lineWidth);
        //        }
        //        else if (orientation == LineOrientation.Vertical)
        //        {
        //            base.Size = new Size(lineWidth, Content.Height);
        //        }
        //        else
        //        {
        //            base.Size = Content;
        //        }
        //    }
        //}

        [Browsable(false)]
        public override Font Font
        {
            get
            {
                return base.Font;
            }
            set
            {
                base.Font = value;
            }
        }

        [Browsable(false)]
        public override Color ForeColor
        {
            get
            {
                return base.ForeColor;
            }
            set
            {
                base.ForeColor = value;
            }
        }

        [Description("Custom light 3D color")]
        [Category("Appearance")]
        [DefaultValue(typeof(SystemColors), "ControlLightLight")]
        public Color Light3dColor
        {
            get
            {
                return this.light3dColor;
            }
            set
            {
                this.light3dColor = value;
                this.UpdatePens();
                this.Invalidate();
            }
        }

        [DefaultValue(Line3DStyle.Flat)]
        [Description("Border style")]
        [Category("Appearance")]
        public Line3DStyle Line3DStyle
        {
            get
            {
                return this.line3DStyle;
            }
            set
            {
                this.line3DStyle = value;
                this.UpdatePens();
                this.UpdateSize();
            }
        }

        [DefaultValue(LineOrientation.Horizontal)]
        [Description("Line orientation")]
        [Category("Appearance")]
        public LineOrientation Orientation
        {
            get
            {
                return this.orientation;
            }
            set
            {
                this.orientation = value;
                this.UpdateSize();
            }
        }

        [Browsable(false)]
        public new int TabIndex
        {
            get
            {
                return base.TabIndex;
            }
            set
            {
                base.TabIndex = value;
            }
        }

        [Browsable(false)]
        public new bool TabStop
        {
            get
            {
                return base.TabStop;
            }
            set
            {
                base.TabStop = value;
            }
        }

        [Browsable(false)]
        public override string Text
        {
            get
            {
                return base.Text;
            }
            set
            {
                base.Text = value;
            }
        }

        #endregion

        #region Properties

        protected override Size DefaultSize
        {
            get
            {
                return new Size(100, 1);
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// 	Verwendete Ressourcen bereinigen.
        /// </summary>
        /// <param name="disposing"> True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False. </param>
        protected override void Dispose(bool disposing)
        {
            if (this.pen1 != null)
            {
                this.pen1.Dispose();
                this.pen1 = null;
            }
            if (this.pen2 != null)
            {
                this.pen2.Dispose();
                this.pen2 = null;
            }

            if (disposing && (this.components != null))
            {
                this.components.Dispose();
            }
            base.Dispose(disposing);
        }

        protected override void OnPaint(PaintEventArgs pe)
        {
            if (this.line3DStyle == Line3DStyle.Flat)
            {
                if (this.orientation == LineOrientation.Horizontal)
                {
                    pe.Graphics.DrawLine(this.pen1, 0, 0, this.Width - 1, 0);
                }
                else if (this.orientation == LineOrientation.Vertical)
                {
                    pe.Graphics.DrawLine(this.pen1, 0, 0, 0, this.Height - 1);
                }
                else if (this.orientation == LineOrientation.DiagonalUp)
                {
                    pe.Graphics.SmoothingMode = SmoothingMode.HighQuality;
                    pe.Graphics.DrawLine(this.pen1, 0, this.Height - 1, this.Width - 1, 0);
                }
                else if (this.orientation == LineOrientation.DiagonalDown)
                {
                    pe.Graphics.SmoothingMode = SmoothingMode.HighQuality;
                    pe.Graphics.DrawLine(this.pen1, 0, 0, this.Width - 1, this.Height - 1);
                }
            }
            else // 3D - colours are set in the Line3DStyle_Set property
            {
                if (this.orientation == LineOrientation.Horizontal)
                {
                    pe.Graphics.DrawLine(this.pen2, 0, 0, this.Width - 1, 0);
                    pe.Graphics.DrawLine(this.pen1, 0, 1, this.Width - 1, 1);
                }
                else if (this.orientation == LineOrientation.Vertical)
                {
                    pe.Graphics.DrawLine(this.pen2, 0, 0, 0, this.Height - 1);
                    pe.Graphics.DrawLine(this.pen1, 1, 0, 1, this.Height - 1);
                }
                else if (this.orientation == LineOrientation.DiagonalUp)
                {
                    pe.Graphics.SmoothingMode = SmoothingMode.HighQuality;
                    pe.Graphics.DrawLine(this.pen2, 0, this.Height - 2, this.Width - 2, 0);
                    pe.Graphics.DrawLine(this.pen1, 1, this.Height - 1, this.Width - 1, 1);
                }
                else if (this.orientation == LineOrientation.DiagonalDown)
                {
                    pe.Graphics.SmoothingMode = SmoothingMode.HighQuality;
                    pe.Graphics.DrawLine(this.pen2, 1, 0, this.Width - 1, this.Height - 2);
                    pe.Graphics.DrawLine(this.pen1, 0, 1, this.Width - 2, this.Height - 1);
                }
            }
        }

        /// <summary>
        /// 	Erforderliche Methode für die Designerunterstützung.
        /// 	Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.
        /// </summary>
        private void InitializeComponent()
        {
            this.components = new Container();
        }

        private void Line_SizeChanged(object sender, EventArgs e)
        {
            if (this.internalResizing)
            {
                return;
            }

            // Only remember the currently alterable dimensions
            if (this.orientation == LineOrientation.Horizontal)
            {
                this.prevWidth = this.Width;
            }
            else if (this.orientation == LineOrientation.Vertical)
            {
                this.prevHeight = this.Height;
            }
            else
            {
                this.prevWidth = this.Width;
                this.prevHeight = this.Height;
            }
        }

        private void UpdatePens()
        {
            if (this.pen1 != null)
            {
                this.pen1.Dispose();
                this.pen1 = null;
            }
            if (this.pen2 != null)
            {
                this.pen2.Dispose();
                this.pen2 = null;
            }

            if (this.line3DStyle == Line3DStyle.Flat)
            {
                this.pen1 = new Pen(this.borderColor, 1);
                this.pen1.DashStyle = this.dashStyle;
            }
            else if (this.line3DStyle == Line3DStyle.Inset)
            {
                this.pen1 = new Pen(this.light3dColor, 1);
                this.pen2 = new Pen(this.dark3dColor, 1);
                this.pen1.DashStyle = this.dashStyle;
                this.pen2.DashStyle = this.dashStyle;
            }
            else if (this.line3DStyle == Line3DStyle.Outset)
            {
                this.pen1 = new Pen(this.dark3dColor, 1);
                this.pen2 = new Pen(this.light3dColor, 1);
                this.pen1.DashStyle = this.dashStyle;
                this.pen2.DashStyle = this.dashStyle;
            }
        }

        private void UpdateSize()
        {
            this.internalResizing = true;
            int lineWidth = (this.line3DStyle != Line3DStyle.Flat) ? 2 : 1;
            if (this.orientation == LineOrientation.Horizontal)
            {
                this.Width = this.prevWidth;
                this.Height = lineWidth;
                //MaximumSize = new Size(0, lineWidth);
            }
            else if (this.orientation == LineOrientation.Vertical)
            {
                this.Width = lineWidth;
                this.Height = this.prevHeight;
                //MaximumSize = new Size(lineWidth, 0);
            }
            else
            {
                this.Width = this.prevWidth;
                this.Height = this.prevHeight;
                //MaximumSize = new Size();
            }
            this.internalResizing = false;
            this.Invalidate();
        }

        #endregion

        //protected override void OnPaintBackground(PaintEventArgs pevent)
        //{
        //    //base.OnPaintBackground(pevent);
        //}

        //protected override CreateParams CreateParams
        //{
        //    get
        //    {
        //        CreateParams cp = base.CreateParams;
        //        cp.ExStyle |= 0x20 /* WS_EX_TRANSPARENT */;
        //        return cp;
        //    }
        //}
    }

    public enum LineOrientation
    {
        Horizontal,

        Vertical,

        DiagonalUp,

        DiagonalDown
    }

    public enum Line3DStyle
    {
        Flat,

        Inset,

        Outset
    }

    public class LineDesigner : ControlDesigner
    {
        #region Public Properties

        public override SelectionRules SelectionRules
        {
            get
            {
                var line = this.Control as Line;
                if (line.Orientation == LineOrientation.Horizontal)
                {
                    return base.SelectionRules & ~(SelectionRules.TopSizeable | SelectionRules.BottomSizeable);
                }
                if (line.Orientation == LineOrientation.Vertical)
                {
                    return base.SelectionRules & ~(SelectionRules.LeftSizeable | SelectionRules.RightSizeable);
                }
                return base.SelectionRules;
            }
        }

        #endregion
    }
}